home *** CD-ROM | disk | FTP | other *** search
/ Giga Games 1 / Giga Games.iso / net / go / prog / sgf2mi13.taz / sgf2mi13 / gogame.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-03-15  |  10.2 KB  |  456 lines

  1. /* #[info:            */
  2. /************************************************************************
  3.  *                                    *
  4.  *          ####   ####   ####     #    #    # #####        *
  5.  *         #      #    # #        # #   ##  ## #            *
  6.  *         #      #    # #       #   #  # ## # #            *
  7.  *         #  ##  #    # #  ##  ####### #    # ###        *
  8.  *         #    # #    # #    # #     # #    # #            *
  9.  *         #    # #    # #    # #     # #    # #            *
  10.  *          ####   ####   ####  #     # #    # #####        *
  11.  *                                    *
  12.  *                Jan van der Steen                *
  13.  *                                    *
  14.  *          Centre for Mathematics and Computer Science        *
  15.  *              Amsterdam, the Netherlands            *
  16.  *                                    *
  17.  *----------------------------------------------------------------------*
  18.  * File      : gogame.c                         *
  19.  * Purpose : Implement functions to maintain a Go Game Data structure    *
  20.  * Version : 1.7                         *
  21.  * Modified: 3/15/93 11:26:56                        *
  22.  * Author  : Jan van der Steen (jansteen@cwi.nl)             *
  23.  ************************************************************************/
  24. /* #]info:            */ 
  25. /* #[include:            */
  26.  
  27. #include <stdio.h>
  28. #include <stdlib.h>
  29. #include <string.h>
  30. #include "tools.h"
  31. #include "gogame.h"
  32. #include "gorules.h"
  33.  
  34. /* #]include:            */ 
  35. /* #[prototype:            */
  36.  
  37. #ifdef __STDC__
  38. #    define    PROTO(s) s
  39. #else
  40. #    define    PROTO(s) ()
  41. #endif
  42.  
  43. /*
  44.  * Memory managers
  45.  */
  46. static CHAIN *    chain_alloc    PROTO((void));
  47. static GOMOVE * move_alloc    PROTO((void));
  48. static TEXT *    text_alloc    PROTO((void));
  49. static GOBAN *    goban_alloc    PROTO((int size));
  50. static int    goban_loop    PROTO((    GOBAN  *goban,
  51.                     GONODE *gonode,
  52.                     int (*f)PROTO((    GOBAN  *goban,
  53.                             GONODE *gonode
  54.                         ))
  55.                 ));
  56. static int    goban_do    PROTO((    GOBAN  *goban,
  57.                     GONODE *gonode,
  58.                     int (*f)PROTO((    GOBAN  *goban,
  59.                             GONODE *gonode
  60.                         ))
  61.                 ));
  62.  
  63. #undef PROTO
  64.  
  65. /* #]prototype:            */ 
  66.  
  67. /* #[text_alloc:        */
  68.  
  69. static TEXT *
  70. text_alloc()
  71. /*
  72.  * Allocate a text list
  73.  */
  74. {
  75.     TEXT *text = (TEXT *) calloc(1, sizeof(TEXT));
  76.  
  77.     if (text == (TEXT *) 0) {
  78.     fprintf(stderr, "Out of memory in text_alloc()\n");
  79.     exit(1);
  80.     }
  81.     return text;
  82. }
  83.  
  84. /* #]text_alloc:        */ 
  85. /* #[text_store:        */
  86.  
  87. void
  88. text_store(gogame, line)
  89. /*
  90.  * The way we deal with incomming text is very IGS specific.
  91.  * Normally we would just append the text to the text buffer.
  92.  * But, since in case of IGS it either contains "say" or "kibitz" messages
  93.  * we have introduced a special format to store these typical cases.
  94.  */
  95. GOGAME *gogame;
  96. char *    line;
  97. {
  98.     TEXT *text;
  99.     TEXT *textlast = gogame->gm_movelast->mv_textlast;
  100.     char *name;
  101.     char *rank;
  102.     char *mesg;
  103.     char *space;
  104.  
  105.     /*
  106.      * The kibitz messages have the format:
  107.      *
  108.      *    <space><username> <rank><optional [space|*]>: <text>
  109.      *
  110.      *    jansteen 3d: My ~connection~ is terrible...    (old IGS)
  111.      *    jansteen 3d : My ~connection~ is terrible...    (rank)
  112.      *    jansteen 3d*: My ~connection~ is terrible...    (rating)
  113.      */
  114.     if (*line != ' ') {
  115.     fprintf(stderr, "C[%s] didn't contain kibitz (skipped)\n", line);
  116.     return;
  117.     };
  118.  
  119.     text = text_alloc();
  120.     if (gogame->gm_movelast->mv_text == (TEXT *) 0)
  121.     gogame->gm_movelast->mv_text = text;
  122.     else
  123.     gogame->gm_movelast->mv_textlast->cc_next = text;
  124.     gogame->gm_movelast->mv_textlast = text;
  125.  
  126.     name  = ++line;
  127.     rank  = strchr(name, ' '); if (rank == (char *) 0) goto error;
  128.     mesg  = strchr(rank, ':'); if (mesg == (char *) 0) goto error;
  129.     *rank = 0; rank += 1;
  130.     *mesg = 0; mesg += 2;
  131.     space = rank+strlen(rank)-1; if (*space == ' ') *space = 0;
  132.     text->cc_name = string_store(name);
  133.     text->cc_rank = string_store(rank);
  134.     text->cc_text = string_store(mesg);
  135.     text->cc_prev = textlast;
  136.     return;
  137. error:
  138.     fprintf(stderr, "Message seems a badly formatted kibitz (ignored)\n");
  139. }
  140.  
  141. /* #]text_store:        */ 
  142. /* #[goban_alloc:        */
  143.  
  144. static GOBAN *
  145. goban_alloc (size)
  146. /*
  147.  * Allocate a new Go board
  148.  */
  149. int size;
  150. {
  151.     GOBAN * goban = (GOBAN *) calloc(1, sizeof(GOBAN));
  152.  
  153.     if (goban == (GOBAN *) 0) {
  154.     fprintf(stderr, "Out of memory in goban_alloc()\n");
  155.     exit(1);
  156.     }
  157.     if (size <= 0) {
  158.     fprintf(stderr, "Board size out of range in goban_alloc(): %d\n", size);
  159.     exit(1);
  160.     }
  161.     goban->gb_node = (GONODE *) calloc(size*size, sizeof(GONODE));
  162.     if (goban->gb_node == (GONODE *) 0) {
  163.     fprintf(stderr, "Out of memory in goban_alloc()\n");
  164.     exit(1);
  165.     }
  166.  
  167.     return goban;
  168. }
  169.  
  170. /* #]goban_alloc:        */ 
  171. /* #[goban_new:            */
  172.  
  173. GOBAN *
  174. goban_new(gogame, s)
  175. /*
  176.  * Allocate and construct a new Go board
  177.  */
  178. GOGAME *gogame;
  179. int    s;        /* Requested size */
  180. {
  181.     PLACE  p;
  182.  
  183.     gogame->gm_goban = goban_alloc(s);
  184.     for (p = 0; p < s*s; p++) {
  185.     NODE(gogame,p)->gn_n = NODE(gogame,p-s);
  186.     NODE(gogame,p)->gn_e = NODE(gogame,p+1);
  187.     NODE(gogame,p)->gn_s = NODE(gogame,p+s);
  188.     NODE(gogame,p)->gn_w = NODE(gogame,p-1);
  189.     }
  190.     for (p = 0      ; p < s  ; p++ ) NODE(gogame,p)->gn_n = (GONODE *) 0;
  191.     for (p = s-1    ; p < s*s; p+=s) NODE(gogame,p)->gn_e = (GONODE *) 0;
  192.     for (p = s*(s-1); p < s*s; p++ ) NODE(gogame,p)->gn_s = (GONODE *) 0;
  193.     for (p = 0      ; p < s*s; p+=s) NODE(gogame,p)->gn_w = (GONODE *) 0;
  194.  
  195.     return gogame->gm_goban;
  196. }
  197.  
  198. /* #]goban_new:            */ 
  199. /* #[goban_loop:        */
  200.  
  201. #ifdef __STDC__
  202. #    define  PROTO(s) s
  203. #else
  204. #    define  PROTO(s) ()
  205. #endif
  206.  
  207. static int
  208. goban_loop(goban, gonode, f)
  209. /*
  210.  * Visit "all" goban points and execute f()
  211.  */
  212. GOBAN  *goban;
  213. GONODE *gonode;
  214. int    (*f)PROTO((GOBAN *goban, GONODE *gonode));
  215. {
  216.     (goban->gb_loop)++;
  217.  
  218.     return goban_do(goban, gonode, f);
  219. }
  220.  
  221. #undef PROTO
  222.  
  223. /* #]goban_loop:        */ 
  224. /* #[goban_do:            */
  225.  
  226. #ifdef __STDC__
  227. #    define  PROTO(s) s
  228. #else
  229. #    define  PROTO(s) ()
  230. #endif
  231.  
  232. static int
  233. goban_do(goban, gonode, f)
  234. /*
  235.  * Visit "all" goban points and execute f()
  236.  */
  237. GOBAN  *goban;
  238. GONODE *gonode;
  239. int    (*f)PROTO((GOBAN *goban, GONODE *gonode));
  240. {
  241.     /*
  242.      * On the goban?
  243.      */
  244.     if (gonode == (GONODE *) 0) return 0;
  245.  
  246.     /*
  247.      * First time?
  248.      */
  249.     if (gonode->gn_loop == goban->gb_loop) return 0;
  250.  
  251.     /*
  252.      * Mark goban point
  253.      */
  254.     gonode->gn_loop = goban->gb_loop;
  255.  
  256.     if (! (*f)(goban, gonode)) return 1;
  257.  
  258.     return (
  259.     goban_do(goban, gonode->gn_n, f) +
  260.     goban_do(goban, gonode->gn_e, f) +
  261.     goban_do(goban, gonode->gn_s, f) +
  262.     goban_do(goban, gonode->gn_w, f) + 1
  263.     );
  264. }
  265.  
  266. #undef PROTO
  267.  
  268. /* #]goban_do:            */ 
  269. /* #[chain_alloc:        */
  270.  
  271. static CHAIN *
  272. chain_alloc()
  273. /*
  274.  * Allocate a new chain
  275.  */
  276. {
  277.     CHAIN *chain = (CHAIN *) calloc(1, sizeof(CHAIN));
  278.  
  279.     if (chain == (CHAIN *) 0) {
  280.     fprintf(stderr, "Out of memory in chain_alloc()\n");
  281.     exit(1);
  282.     }
  283.     return chain;
  284. }
  285.  
  286. /* #]chain_alloc:        */ 
  287. /* #[move_alloc:        */
  288.  
  289. static GOMOVE *
  290. move_alloc()
  291. /*
  292.  * Allocate a new move
  293.  */
  294. {
  295.     GOMOVE *move = (GOMOVE *) calloc(1, sizeof(GOMOVE));
  296.  
  297.     if (move == (GOMOVE *) 0) {
  298.     fprintf(stderr, "Out of memory in move_alloc()\n");
  299.     exit(1);
  300.     }
  301.     return move;
  302. }
  303.  
  304. /* #]move_alloc:        */ 
  305. /* #[move_store:        */
  306.  
  307. void
  308. move_store(gogame, side, place)
  309. GOGAME *gogame;
  310. int    side;
  311. PLACE    place;
  312. {
  313.     GOMOVE *move;
  314.     GOMOVE *last;
  315.     char   *error;
  316.  
  317.     if (place == ('t'-'a') + ('t'-'a') * gogame->gm_size) {
  318.     /*
  319.      * The SGF format uses [tt] for passes,
  320.      * i.e. a move outside the board.
  321.      * We will just ignore them for the moment,
  322.      * till we figured out how to deal with passes properly.
  323.      */
  324.     return;
  325.     }
  326.  
  327.     move = move_alloc();
  328.     last = gogame->gm_movelast;
  329.     if (gogame->gm_move == (GOMOVE *) 0) gogame->gm_move          = move;
  330.     else                 gogame->gm_movelast->mv_next = move;
  331.     gogame->gm_movelast                              = move;
  332.  
  333.     move->mv_place = NODE(gogame,place);
  334.     move->mv_side  = side;
  335.     move->mv_nr       = ++(gogame->gm_movenr);
  336.     move->mv_prev  = last;
  337.     switch (rules_check(gogame, place, side)) {
  338.     case RULES_LEGAL:    return;
  339.     case RULES_OUTSIDE:  error = "Not on the board";    break;
  340.     case RULES_SUICIDE:  error = "Suicide move";        break;
  341.     case RULES_KO:         error = "Ko capture not allowed";    break;
  342.     case RULES_OCCUPIED: error = "Occupied point";        break;
  343.     default:         error = "Unknown error";        break;
  344.     }
  345.     /*
  346.      * Emit error info
  347.      */
  348.     fprintf(stderr, "Illegal move: %s (move: %d)\n", error, move->mv_nr);
  349.  
  350.     /*
  351.      * Make the place vacant
  352.      */
  353.     move->mv_side  = FREE;
  354. }
  355.  
  356. /* #]move_store:        */ 
  357. /* #[capture_store:        */
  358.  
  359. void
  360. capture_store(gogame, gonode)
  361. /*
  362.  * Add the stone at gonode to the captured stone list
  363.  */
  364. GOGAME *gogame;
  365. GONODE *gonode;
  366. {
  367.     CHAIN  *c = chain_alloc();
  368.     GOMOVE *m = gogame->gm_movelast;
  369.  
  370.     c->ch_stone = gonode->gn_stone;
  371.  
  372.     /*
  373.      * Insert the stone
  374.      */
  375.     c->ch_next       = m->mv_captured;
  376.     m->mv_captured = c;
  377. }
  378.  
  379. /* #]capture_store:        */ 
  380. /* #[game_alloc:        */
  381.  
  382. GOGAME *
  383. game_alloc()
  384. /*
  385.  * Allocate a new game
  386.  */
  387. {
  388.     GOGAME *g = (GOGAME *) calloc(1, sizeof(GOGAME));
  389.  
  390.     if (g == (GOGAME *) 0) {
  391.     fprintf(stderr, "Out of memory in game_alloc()\n");
  392.     exit(1);
  393.     }
  394.     /*
  395.      * Allocate Go board
  396.      */
  397.     g->gm_goban = goban_new(g, MAXSIZE);
  398.     g->gm_size  = MAXSIZE;
  399.  
  400.     return g;
  401. }
  402.  
  403. /* #]game_alloc:        */ 
  404. /* #[game_free:            */
  405.  
  406. void
  407. game_free(gogame)
  408. /*
  409.  * Free the resources associated with a game
  410.  */
  411. GOGAME *gogame;
  412. {
  413.     GOGAME *g = gogame;
  414.     GOMOVE *m;
  415.     GOMOVE *mn;
  416.     CHAIN  *c;
  417.     CHAIN  *cn;
  418.  
  419.     /* Moves + captured stones    */
  420.     for (m = g->gm_move; m != (GOMOVE *) 0; m = mn) {
  421.     mn = m->mv_next;
  422.     for (c = m->mv_captured; c != (CHAIN *) 0; c = cn) {
  423.         cn = c->ch_next;
  424.         free(c);
  425.     }
  426.     free(m);
  427.     }
  428.  
  429.     /* Goban + Gonodes */
  430.     if (g->gm_goban != (GOBAN *) 0) {
  431.     if (g->gm_goban->gb_node != (GONODE *) 0) free(g->gm_goban->gb_node);
  432.     free(g->gm_goban);
  433.     }
  434.  
  435.     /* Game information    */
  436.     if (g->gm_event    != (char  *) 0) free(g->gm_event   );
  437.     if (g->gm_user    != (char  *) 0) free(g->gm_user    );
  438.     if (g->gm_view    != (char  *) 0) free(g->gm_view    );
  439.     if (g->gm_game    != (char  *) 0) free(g->gm_game    );
  440.     if (g->gm_name    != (char  *) 0) free(g->gm_name    );
  441.     if (g->gm_black    != (char  *) 0) free(g->gm_black   );
  442.     if (g->gm_brank    != (char  *) 0) free(g->gm_brank   );
  443.     if (g->gm_btime    != (char  *) 0) free(g->gm_btime   );
  444.     if (g->gm_bleft    != (char  *) 0) free(g->gm_bleft   );
  445.     if (g->gm_white    != (char  *) 0) free(g->gm_white   );
  446.     if (g->gm_wrank    != (char  *) 0) free(g->gm_wrank   );
  447.     if (g->gm_wtime    != (char  *) 0) free(g->gm_wtime   );
  448.     if (g->gm_wleft    != (char  *) 0) free(g->gm_wleft   );
  449.     if (g->gm_komi    != (char  *) 0) free(g->gm_komi    );
  450.     if (g->gm_date    != (char  *) 0) free(g->gm_date    );
  451.     if (g->gm_place    != (char  *) 0) free(g->gm_place   );
  452.     if (g->gm_result    != (char  *) 0) free(g->gm_result  );
  453. }
  454.  
  455. /* #]game_free:            */ 
  456.